import { Server } from 'socket.io'
import { danmakuConfig } from '../../config/danmaku'
import { User } from '../../models/User'
import { AppError } from '../../utils/AppError'
import { RedisService } from '../redis/RedisService'
import { RoomStateService } from '../room/RoomStateService'
import { DanmakuFilter } from './DanmakuFilter'

export class DanmakuService {
  private io: Server
  private redis: RedisService
  private filter: DanmakuFilter
  private roomState: RoomStateService

  constructor(io: Server) {
    this.io = io
    this.redis = new RedisService()
    this.filter = new DanmakuFilter()
    this.roomState = new RoomStateService()
  }

  // 发送弹幕
  async sendDanmaku(data: {
    userId: string
    roomId: string
    content: string
    type?: 'normal' | 'advanced' | 'special'
    color?: string
    position?: 'scroll' | 'top' | 'bottom'
    fontSize?: number
    mode?: 'normal' | 'subtitle'
  }) {
    const {
      userId,
      roomId,
      content,
      type = 'normal',
      color,
      position = 'scroll',
      fontSize,
      mode = 'normal',
    } = data

    // 检查用户权限
    await this.roomState.checkPermission(roomId, userId, 'danmaku')

    // 检查发送频率
    await this.checkSendFrequency(userId)

    // 内容过滤
    const filteredContent = await this.filter.process(content)
    if (!filteredContent) {
      throw new AppError(400, '弹幕内容包含敏感词')
    }

    // 创建弹幕对象
    const danmaku = {
      id: `dm_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
      userId,
      roomId,
      content: filteredContent,
      type,
      color: color || '#FFFFFF',
      position,
      fontSize: fontSize || danmakuConfig.defaultFontSize,
      mode,
      timestamp: Date.now(),
    }

    // 获取发送者信息
    const sender = await this.getUserInfo(userId)
    const fullDanmaku = { ...danmaku, sender }

    // 广播弹幕
    this.io.to(roomId).emit('danmaku', fullDanmaku)

    // 保存弹幕记录
    await this.saveDanmaku(fullDanmaku)

    // 更新统计信息
    await this.updateStats(roomId, userId)

    return fullDanmaku
  }

  // 获取弹幕历史
  async getDanmakuHistory(roomId: string, limit: number = 100) {
    const records = await this.redis.lrange(`danmaku:history:${roomId}`, 0, limit - 1)
    return records.map((r) => JSON.parse(r))
  }

  // 检查发送频率
  private async checkSendFrequency(userId: string) {
    const key = `danmaku:frequency:${userId}`
    const count = await this.redis.incr(key)

    if (count === 1) {
      await this.redis.expire(key, danmakuConfig.frequency.interval)
    }

    if (count > danmakuConfig.frequency.maxMessages) {
      throw new AppError(429, '发送太频繁，请稍后再试')
    }
  }

  // 获取用户信息
  private async getUserInfo(userId: string) {
    const user = await User.findById(userId).select('nickname avatar level badges vipLevel')

    return {
      userId,
      nickname: user.nickname,
      avatar: user.avatar,
      level: user.level,
      badge: user.badges[0],
      vipLevel: user.vipLevel,
    }
  }

  // 保存弹幕记录
  private async saveDanmaku(danmaku: any) {
    const key = `danmaku:history:${danmaku.roomId}`
    await this.redis.lpush(key, JSON.stringify(danmaku))
    await this.redis.ltrim(key, 0, danmakuConfig.history.maxLength - 1)
  }

  // 更新统计信息
  private async updateStats(roomId: string, userId: string) {
    const multi = this.redis.multi()

    // 更新房间弹幕数
    multi.hincrby(`room:${roomId}:stats`, 'danmaku', 1)
    multi.hincrby(`room:${roomId}:stats`, 'totalDanmaku', 1)

    // 更新用户弹幕数
    multi.hincrby(`user:${userId}:stats`, 'danmaku', 1)
    multi.hincrby(`user:${userId}:stats`, 'totalDanmaku', 1)

    // 更新日排行
    const today = new Date().toISOString().split('T')[0]
    multi.zincrby(`danmaku:rank:${roomId}:${today}`, 1, userId)

    await multi.exec()
  }

  // 获取弹幕排行
  async getDanmakuRanking(roomId: string, type: 'daily' | 'weekly' | 'monthly' = 'daily') {
    const key = `danmaku:rank:${roomId}:${this.getRankingKey(type)}`
    const ranking = await this.redis.zrevrange(key, 0, 49, 'WITHSCORES')

    const result = []
    for (let i = 0; i < ranking.length; i += 2) {
      const userId = ranking[i]
      const count = parseInt(ranking[i + 1])
      const user = await User.findById(userId).select('nickname avatar level badges')

      result.push({
        rank: i / 2 + 1,
        userId,
        nickname: user.nickname,
        avatar: user.avatar,
        level: user.level,
        badge: user.badges[0],
        count,
      })
    }

    return result
  }

  // 获取排行榜Key
  private getRankingKey(type: string): string {
    const now = new Date()
    if (type === 'daily') {
      return now.toISOString().split('T')[0]
    } else if (type === 'weekly') {
      const weekStart = new Date(now.setDate(now.getDate() - now.getDay()))
      return weekStart.toISOString().split('T')[0]
    } else {
      return now.toISOString().slice(0, 7)
    }
  }
}
